package com.theorydance.esoperator.utils;

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;

/**
 * 自定义缓存守护线程，按照配置时间，进行自动清理过期缓存
 */
@Slf4j
public class CacheDaemon extends Thread{

	/**
	 * 存放缓存对象（说明：一个缓存对象中，存在很多键值对）
	 */
	private static List<WeakReference<Cache<?, ?>>> cacheList = new LinkedList<>();
	
	/**
	 * 是否启动了守护线程，定时清理缓存集合中各个缓存中的无效键值对
	 */
	private static volatile boolean startup = false;
	
	/**
	 * 守护线程启动的频率设置，3小时
	 */
	private final static long INTERVAL = 3*60*60*1000; // 3小时，守护进程清理缓存时间
	
	/**
	 * 将缓存，加入到缓存队列中，守护线程，定时遍历缓存队列，清空里面的无效缓存键值对
	 * @param cache 缓存对象（内含多个键值对）
	 */
	public static void addCacheInstance(Cache<?, ?> cache) {
		
		// 加入到缓存队列，使用弱引用，允许被释放
		cacheList.add(new WeakReference<Cache<?, ?>>(cache));
		
		/*
		 * 双重校验，是否启动守护线程（定时清理缓存中的无效键值对）
		 */
		if(!startup) {
			synchronized (CacheDaemon.class) {
				if(!startup) {
					// 只启动一个守护线程
					startup = true;
					CacheDaemon daemon = new CacheDaemon();
					// 将其设置为守护线程
					daemon.setDaemon(true);
					daemon.start();
					log.info("启动缓存daemon进程");
				}
			}
		}
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep(INTERVAL);
			} catch (InterruptedException e) {}
			log.info("启动守护线程，清理缓存中的数据");
			
			// 遍历缓存集合中的每一个缓存，将其中每个缓存中的无效过期键值对给清理掉
			for (int i = 0; i < cacheList.size(); i++) {
				try {
					WeakReference<Cache<?, ?>> weakReference = cacheList.get(i);
					Cache<?, ?> cache = weakReference.get();
					if(cache != null) {
						// 此时仍然可能报null
						cache.expireAndClear();
					}else {
						// 清理cacheList中无效的weakReference
						cacheList.remove(i--);
					}
				} catch (Exception e) {}
			}
		}
	}
	
}
